package li.brauch.semesterarbeit.radio.views;

import li.brauch.semesterarbeit.radio.AbstractRadio;
import li.brauch.semesterarbeit.radio.IRadio;
import li.brauch.semesterarbeit.radio.RadioPlugin;
import li.brauch.semesterarbeit.radio.RadioPropertyListener;
import li.brauch.semesterarbeit.radio.controller.RadioController;
import li.brauch.semesterarbeit.radio.model.StationTuneModel;
import li.brauch.semesterarbeit.radio.model.StationTuneResultModel;
import li.brauch.semesterarbeit.radio.sound.MP3Player;
import li.brauch.semesterarbeit.radio.sound.MP3PlayerListener;
import li.brauch.semesterarbeit.radio.sound.Volume;
import li.brauch.semesterarbeit.radio.views.util.ColorStore;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.part.ViewPart;

public class RadioViewPart extends ViewPart implements RadioPropertyListener {
	
	private RadioController controller;
	
	private AbstractRadio radio;
	private MP3Player player;
	private Volume volume;
	
	private StationTuneModel tuneModel;
	private StationTuneResultModel resultModel;
	
	private TunerPanel tunerPanel;
	private SelectPanel selectPanel;
	private PlayerPanel playerPanel;	
	
	private Composite parent;
	
	public RadioViewPart() {
		super();
	}

	@Override
	public void createPartControl(Composite parent) {		
		
		this.parent = parent;
		
		tunerPanel = new TunerPanel(parent);
		tunerPanel.setTitle("Choose a station");
		
		if (radio != null) {
			String[] types = radio.getStationTypes();		
			tunerPanel.setStationTypes(types);
		}
		tunerPanel.addAdjustPanelListener(new TunerPanelListener() {
						
			public void adjustClicked(String stationType, String stationName) {
				
				
				tuneModel = new StationTuneModel();
				tuneModel.setType(stationType);
				tuneModel.setName(stationName);
				controller.tune(RadioViewPart.this);
			}
			
			public void linkClicked(String link) {
				PreferenceDialog pref = PreferencesUtil.createPreferenceDialogOn(Display.getCurrent().getActiveShell(), RadioPlugin.PLUGIN_ID, null, null);
				if (pref != null)
					pref.open();
			}
		});
		
		selectPanel = new SelectPanel(parent);		
		selectPanel.setLabel("The station is ambiguous. Please choose one.");
		selectPanel.addSearchPanelListener(new SelectPanelListener() {
			
			public void stationSelected(String name) {
				
				tuneModel.setName(name);
				controller.tune(RadioViewPart.this);
				
			}
		});
		
		playerPanel = new PlayerPanel(parent);
		playerPanel.addPlayerPanelListener(new PlayerPanelListener() {

			public void banClicked() {
				controller.ban(RadioViewPart.this);
			}

			public void buyClicked() {				
				controller.buy(RadioViewPart.this);
			}

			public void loveClicked() {
				controller.love(RadioViewPart.this);
			}

			public void pauseClicked() {
				controller.pause(RadioViewPart.this);
			}

			public void resumeClicked() {
				controller.resume(RadioViewPart.this);
			}

			public void skipClicked() {
				controller.skip(RadioViewPart.this);
			}

			public void stopClicked() {
				controller.stop(RadioViewPart.this);
			}
			
			public void muteClicked() {
				volume.toggleMute();
			}
			
			public void volumeChanged(int v) {
				volume.setVolume(v);
			}
			
		});
						
		StackLayout layout = new StackLayout();
		layout.topControl = tunerPanel;
		
		parent.setLayout(layout);
		parent.setBackground(ColorStore.BACKGROUND);
		
		// try to login
		controller.login(this);
	}

	@Override
	public void setFocus() {
		
	}
	
	@Override
	public void init(IViewSite site) throws PartInitException {
		super.init(site);
		
		// initialize selected radio from preferences
		IExtensionRegistry registry = RegistryFactory.getRegistry();
		IExtensionPoint extensionPoint = registry.getExtensionPoint("li.brauch.semesterarbeit.radio.IRadio");
		
		final IConfigurationElement[] elements = extensionPoint.getConfigurationElements();
		
		IPreferenceStore store = RadioPlugin.getDefault().getPreferenceStore();
		store.addPropertyChangeListener(new IPropertyChangeListener() {

			public void propertyChange(PropertyChangeEvent event) {
				
				if ("radioImpl".equals(event.getProperty())) {
					for (IConfigurationElement element : elements) {
						if (element.getAttribute("class").equals(event.getNewValue())) {
							try {
								
								// remove listener from old radio
								radio.removeRadioPropertyListener(RadioViewPart.this);
								
								// set new radio plugin
								radio = (AbstractRadio) element.createExecutableExtension("class");
								
								// add listener to new radio
								radio.addRadioPropertyListener(RadioViewPart.this);
								
								// try to login
								controller.reset(RadioViewPart.this); 
								
								
							} catch (CoreException e) {
								showErrorMessageBox(e.getMessage());
							}
							break;
						}
					}
				}
			}
		});
		
		String radioImpl = store.getString("radioImpl");
		if (radioImpl != null && !"".equals(radioImpl)) {
			for (IConfigurationElement element : elements) {
				if (element.getAttribute("class").equals(radioImpl)) {
					try {
						// instantiate last selected radio plugin
						radio = (AbstractRadio) element.createExecutableExtension("class");
						
						// add listener to new radio
						radio.addRadioPropertyListener(RadioViewPart.this);
						
					} catch (CoreException e) {
						showErrorMessageBox(e.getMessage());
					}
					break;
				}
			}
		}
		
		// create mp3 player
		player = new MP3Player();
		player.addMP3PlayerListener(new MP3PlayerListener() {
		
			public void playbackFinished() {
				// play next track
				controller.play(RadioViewPart.this);
			}
			
			public void positionUpdated(long position) {
				playerPanel.updateTrackPosition(position);
			}
			
		});
		
		// create volume controller
		try {
			volume = new Volume();
		} catch (Exception e) {
			showErrorMessageBox(e.getMessage());
		}
		
		// initial state is ready
		setState(RadioController.INIT);
	}
	
	public void radioPropertyChanged() {
		// reset controller, this cause new initialization of the current radio implementation with new radio properties
		controller.reset(this);
	}
	
	public void dispose() {
		if (radio != null) {
			
		}
		player.stop();
		super.dispose();
	}
	
	public IRadio getRadio() {
		return radio;
	}
	
	public void setState(RadioController state) {
		this.controller = state;
	}

	public MP3Player getPlayer() {
		return player;
	}

	public Volume getVolume() {
		return volume;
	}

	public void showTunerPanel() {
		StackLayout layout = (StackLayout) parent.getLayout();
		layout.topControl = tunerPanel;
		parent.layout();
	}
	
	public void showSelectPanel() {
		StackLayout layout = (StackLayout) parent.getLayout();
		layout.topControl = selectPanel;
		parent.layout();
	}
	
	public void showPlayerPanel() {
		StackLayout layout = (StackLayout) parent.getLayout();
		layout.topControl = playerPanel;
		parent.layout();
	}
	
	public void showErrorMessageBox(String message) {		
		MessageBox messageBox = new MessageBox(getViewSite().getShell(), SWT.OK | SWT.ICON_ERROR);
		messageBox.setMessage(message);
		messageBox.open();
	}

	public StationTuneModel getStationTuneModel() {
		return tuneModel;
	}

	public void setStationTuneModel(StationTuneModel adjustModel) {
		this.tuneModel = adjustModel;
	}

	public StationTuneResultModel getStationTuneResultModel() {
		return resultModel;
	}

	public void setStationTuneResultModel(StationTuneResultModel resultModel) {
		this.resultModel = resultModel;
	}

	public TunerPanel getTunerPanel() {
		return tunerPanel;
	}

	public SelectPanel getSelectPanel() {
		return selectPanel;
	}

	public PlayerPanel getPlayerPanel() {
		return playerPanel;
	}
	
}
